home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 February
/
EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso
/
earcd
/
assembler
/
progasm1.lha
/
LEZIONI
/
LEZIONE2.TXT
< prev
next >
Wrap
Text File
|
1994-10-30
|
30KB
|
705 lines
CORSO DI ASSEMBLER - LEZIONE 2
Avete capito esattamente come funziona il sorgente LEZIONE1a.s???
Se non lo avete capito allora siete da neuro, e dovete smettere il corso.
Ora andiamo ad approfondire il linguaggio del 68000. Ho voluto anticipare
col primo sorgente il fatto che il processore serve grossomodo per
organizzare tutte le cose, ma che da solo non fa che cambiare valori
nella sua memoria; mettendo certi valori in aree particolari di memoria
come $dffxxx o $bfexxx si da corrente ai piedini dei chip della grafica,
del suono e delle porte, e di conseguenza si puo', come nell'esempio
precedente, cambiare il colore dello schermo, o leggendo queste locazioni
sapere a che linea il pennello elettronico sia arrivato o se il bottone del
mouse e' premuto. Per fare un gioco o una demo e' necessario usare un gran
numero di questi indirizzi, detti REGISTRI, e quindi e' necessario conoscerli
almeno quanto il linguaggio del 68000, (MOVE,JSR,ADD,SUB etc.) con cui si
impostano.
Per la programmazione di questo tipo come ho gia detto non si usano le LIBRERIE
del ROM kickstart 1.2/1.3/2.0/3.0 (Ovvero le sue routines, o sottoprogrammi
che consentono di aprire una finestra workbench o leggere un file, ad esempio)
cioe' si usano pochissimo: ad esempio per evitare di far andare in guru il
workbench o per disabilitare il multitasking.
Ritengo necessario quindi in questa lezione n.2 di approfondire l'uso del
68000, una volta che si e' capito quale sia il suo ruolo.
La cosa piu' importante da imparare sono i modi di indirizzamento del
processore, piu' che i comandi in se, infatti una volta imparato quello,
ogni comando usa la stessa sintassi per l'indirizzamento e basta sapere
che cosa fa il comando. Abbiamo gia detto che il processore opera sulla
memoria che e' divisa in locazioni o indirizzi, la cui unita' di misura
e' il byte, e solitamente l'indirizzo e' in formato esadecimale, cioe' in
un formato numerico diverso da quello decimale, avendo infatti base 16.
Questo non e' assolutamente un problema: mentre con i numeri decimali una
sequenza di 30 numeri ad esempio fa: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 etc,
in esadecimale fa 1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,10,11,12,13,14,15,16,17,18,
19,1a,1b,1c,1d,1e etc., cioe' nei numeri esadecimali si trovano anche le prime
6 lettere dell'alfabeto come se a fosse un 10, b un 11 eccetera; per convertire
un numero da esadecimale a decimale o viceversa basta usare il comando "?"
dell'asmone: per esempio facendo "?10000" si otterra' $2710, il corrispondente
valore in esadecimale (i numeri esadecimali cominciano col $, quelli decimali
non sono preceduti da niente e quelli binari da un %). I numeri esadecimali
sono usati perche' sono piu' vicini al modo di pensare del computer che e'
ovviamente BINARIO, cioe' composto di soli 0 ed 1.
Come esempio per iniziare a capire i vari modi di indirizzamento del 68000
useremo il comando CLR, che azzera la locazione di memoria indicata:
CLR.B $40000 ; vi ricordate la differenza tra .B, .W e .L?
Questa istruzione "pulira'", cioe' azzerera' il byte n. $40000, ossia
l'indirizzo $40000. Questo e' il caso piu' semplice, detto ASSOLUTO; cioe'
si indica direttamente in che indirizzo fare il CLR; nell'assemblatore sono
in uso le LABEL, che servono ad identificare un punto del programma, in
cui puo' esserci per esempio un byte da indicare: in questo caso invece di
scrivere l'indirizzo si scrivera' il nome della LABEL; l'assemblatore allora
scrivera' l'indirizzo effettivo del byte in questione: ad esempio, se
modificassimo cosi' il nostro primo listato:
Waitmouse:
move.w $dff006,$dff180 ; metti il valore di $dff106 in $dff180
; cioe' il VHPOSR nel COLOR0
btst #6,$bfe001 ; tasto sinistro del mouse premuto?
bne.s Waitmouse ; se no ritorna a waitmouse e ripeti
; (il .s e' un equivalente del .b per questo
; tipo di comandi: bne.s = bne.b)
clr.b dato1 ; AZZERA DATO1
rts ; esci
dato1:
dc.b $30 ; dc.b significa METTI IN MEMORIA IL SEGUENTE BYTE
; in questo caso viene messo un $30 sotto dato1:
Prima di uscire con l'RTS si azzererebbe il byte contrassegnato con la label
dato1:, che sarebbe allocato nella fase di assemblaggio (o compilazione)
a qualche indirizzo assoluto ben preciso, ad esempio se il programma
fosse assemblato dall'ASMONE a partire da $50000, si troverebbe in memoria
dopo l'assemblaggio un CLR.B $5001c, cioe' l'indirizzo reale di dato1: ,
non certo CLR.B DATO1, essendo dato1: un nome dato dal programmatore per
contrassegnare il dc.b $30; di qui si intuisce anche l'utilita' delle label,
infatti se si dovesse scrivere il listato indicando l'indirizzo numerico
tutte le volte, nel caso che si aggiungesse una routine nel mezzo del
programma si dovrebbero riscrivere tutti gli indirizzi. Per vedere a quale
indirizzo vengono assemblate le label, basta usare il comando D dell'ASMONE:
ad esempio dopo aver assemblato LEZIONE1a.s facendo "D waitmouse" otterrete il
disassemblato della memoria a partire da waitmouse, e nel listato non
appariranno le label, ma gli indirizzi reali.
Nei sorgenti esempio del corso noterete che non vengono mai indicati indirizzi
numerici, ma solo LABEL, a parte gli indirizzi speciali come $dffxxx o $bfexxx.
Nell'ultimo esempio ho usato un dc.b, che e' un comando dell'assemblatore che
serve per inserire bytes definiti; per esempio per inserire un $12345678 in
un dato punto del programma, dovro' usare il comando DC, e lo posso usare
nelle 3 forme .B (BYTE), .W (WORD) e .L (LONGWORD):
dc.b $12,$34,$56,$78 ; in bytes
dc.w $1234,$5678 ; in words
dc.l $12345678 ; in longwords
Questo comando si usa anche per mettere delle frasi in memoria, ad esempio
per mettere nel listato il testo che dovra' essere stampato a video da una
routine di PRINT che stampi cio' che e' alla label TESTO:
TESTO:
dc.b "tanti saluti"
oppure:
dc.b 'tanti saluti'
Di solito si termina il testo con uno zero:
dc.b "tanti saluti",0
Bisogna ricordarsi di mettere il testo tra virgolette e di usare il dc.b,
non il dc.w o il dc.l!! I caratteri sono lunghi un byte ciascuno, e
corrispondono ad un certo byte: ad esempio provate a fare ?"a" , e vedrete
che corrisponde a $61, quindi scrivere dc.b "a" sara' equivalente a
scrivere dc.b $61. Attenzione che le lettere grandi hanno valore diverso!
un "A" per esempio e' $41. L'uso piu' comune del dc.b e' quello di definire
byte, word, o zone piu' grandi dove verranno tenuti dei dati, ad esempio
se si volesse fare un programma che registri il numero di volte che si preme
un certo tasto, bisognera' definire una label seguita per esempio da un byte
azzerato, ed ogni volta si aggiungera' 1 con il comando ADD a quella label,
ossia a quel byte sotto la label, e all'uscita bastera' leggere il valore
del byte:
; se il tasto e' premuto allora ADDQ.B #1,NUMPREMUTO, ossia
; aggiungi uno al byte sotto la label numpremuto.
NUMPREMUTO:
dc.b 0
All'uscita del programma lo 0 iniziale sara' cambiato nel numero di volte
che il tasto e' stato premuto. Un esempio simile e' in LEZIONE2a.s, che
contiene anche un ampio commento. Vi consiglio di caricarlo in un altro
buffer di testo: per selezionare uno dei 10 disponibili basta premere un
tasto da F1 a F10, se per esempio avete LEZIONE2.TXT nel buffer di F1,
premete F2, e caricateci LEZIONE2a.s con il comando "R". In seguito potete
caricare LEZIONE2b.s e i seguenti nel buffer di F3,F4..., in modo da averli
sempre a disposizione premendo un solo tasto; e' meglio comunque se seguite
la LEZIONE.TXT, e man mano che trovate l'indicazione del sorgente esempio,
continuate caricandolo in un altro buffer, eseguendolo e verificandolo,
dopodiche' ritornate a leggere la LEZIONE da dove eravate: questo credo
sia il miglior sistema per imparare, infatti si fa un po di teoria e si
verifica subito.
Avete letto i commenti di LEZIONE2a.S?
Avrete visto l'importanza che hanno il byte, la word e la longword: per
quanto riguarda il binario, per contare i bit, si comincia da destra e
si va verso sinistra, al "contrario" insomma, e si parte da 0, non da 1, dunque
un byte (che ha 8 bit) parte 0 e va fino al 7. Per esempio in questo numero:
%000100010000
Sono "accesi" i bit 4 e 8. Per aiutarvi a numerarli potete fare cosi':
;5432109876543210 - un utilizzo intelligente del ;
move.w #%0011000000100100,$dffxxx
In questo caso sono "accesi" i bit 2,5,12 e 13 della WORD.
Ricordo che un byte ha 8 bit, una word ne ha 16 (da 0 a 15), una longword ne
ha 32 (da 0 a 31).
Nell'istruzione
BTST #6,$bfe001
Si controlla se il bit 6 del byte $bfe001 e' azzerato: se fosse:
;76543210
%01000000
Il bit 6 e' invece ad 1, dunque il mouse non e' premuto!!!
Per ricapitolare, un BYTE e' fatto di 8 bit: per indicarli, il primo a destra
e' il bit 0, detto anche BIT MENO SIGNIFICATIVO. La numerazione procede da
destra verso sinistra fino al 7, (ossia l'ottavo perche' si parte da 0 anziche'
da 1: 01234567, ossia 8 bit); il bit 7 e' detto BIT PIU' SIGNIFICATIVO.
E' piu' significativo perche' conta di piu' allo stesso modo in cui conta di
piu', nel bigliettone da centomila, l'uno piu' a sinistra degli zeri piu' a
destra.
Un byte, al massimo puo' valere 255, ossia %11111111.
Una WORD invece e' fatto di 16 bit, ovvero due byte, allo stesso modo si parte
da destra col bit 0, sempre il meno significativo, fino al bit 15 ultimo a
sinistra, il piu' significativo. Al massimo puo' contenere 65535.
Una LongWord e' fatta di 32 bit, da 0 a 31, ossia 4 bytes, o 2 word, o se
preferite una word e 2 bytes, insomma sempre 32 bit attaccati l'uno all'altro
che al massimo possono contenere 4294967299 (4 miliardi!! come la lotteria!).
Ora procederemo con diversi modi di indirizzare: abbiamo visto che se
facciamo ad esempio un CLR.W $100, azzereremo le locazioni $100 e $101,
ossia una word a partire da $100 (essendo una word 2 bytes, e le locazioni
divise in bytes, puliremo 2 bytes!!). Allo stesso modo un MOVE.B $100,$200
copiera' il contenuto di $100 in $200. Questo si puo' indicare anche con
le LABEL invece di specificare l'indirizzo, ad esempio MOVE.B LABEL1,LABEL2,
ovvero copia il byte di LABEL1 in LABEL2. Ci sono pero' anche diversi modi
di indirizzare, infatti posso fare un MOVE.L #$50000,LABEL2, ossia mettere
un valore FISSO in LABEL2. Se ad esempio LABEL2 fosse all'indirizzo $60000,
muoveremmo il valore $00050000 in $60000, ovvero i bytes facendo un M $60000:
00 05 00 00. Infatti quando c'e' il simbolo del cancelletto (#) prima di
un numero o di una label significa che si sta muovendo un valore stabilito,
e non il valore contenuto nell'indirizzo indicato con quel valore, come
avviene se non ci sono cancelletti prima del numero o della LABEL. Per
esempio analizziamo questi 2 casi:
1) MOVE.L $50000,$60000 ; il valore contenuto negli indirizzi
; di memoria $50000,$50001,$50002,$50003
; vengono copiati in $60000,
; $60001,$60002,$60003, ossia una longword
; composta di 4 bytes viene copiata da un
; indirizzo all'altro.
2) MOVE.L #$50000,$60000 ; Questa volta in $60000 viene messo il
; numero indicato dopo il cancelletto,
; ossia $50000. Da notare che questa
; volta l'indirizzo $50000 non viene letto
; e non c'entra assolutamente, viene
; implicato solo il $60000.
Se si usano delle label, non ci sono cambiamenti:
1) MOVE.L CANE,GATTO ; Il contenuto della longword cane, ossia
; $00123456 viene copiato nella longword
; GATTO (infatti $123456 e' la prima cosa
; sotto la label CANE)
prima dell'istruzione:
CANE:
dc.l $123456
GATTO:
dc.l 0
dopo l'istruzione:
CANE:
dc.l $123456
GATTO:
dc.l $123456
2) MOVE.L #CANE,GATTO ; Questa volta l'INDIRIZZO della label
; CANE viene copiato nella label GATTO
prima dell'istruzione: ; SUPPONIAMO CHE LA LABEL CANE: sia alla locazione
; $34500, cioe' facendo un M CANE dopo aver assemblato
; compare un :
; 00034500 00 12 34 56 00 00 00 00 .....
; (cane) (gatto)
CANE:
dc.l $123456
GATTO:
dc.l 0
dopo l'istruzione:
CANE:
dc.l $123456
GATTO:
dc.l $34500 ; ossia DOVE E' LA LABEL CANE IN MEMORIA.
Da notare che se si faceva un MOVE.W #CANE,GATTO o un MOVE.B #CANE,GATTO
l'assemblatore avrebbe dato un errore, in quanto un INDIRIZZO e' lungo
una LONGWORD. In memoria un MOVE.L #LABEL,LABEL si trasforma in un istruzione
del tipo MOVE.L #$12345,$12345, ossia l'assemblatore scrive l'indirizzo
reale al posto delle label. Questo lo potete verificare con LEZIONE2b.s.
Ora affronteremo gli altri indirizzamenti con i registri (che sono piu'
difficili); come avevo gia' accennato, ci sono 8 registri dati e 8 registri
indirizzi: ossia D0,D1,D2,D3,D4,D5,D6,D7 sono i registri DATI, mentre
a0,a1,a2,a3,a4,a5,a6,a7 sono i registri indirizzi. Premetto che il registro
A7 e' detto anche SP o STACK POINTER, ed e' un registro particolare di cui
parleremo dopo, quindi considerate di usare i registri indirizzi solo fino ad
a6. questi indirizzi sono lunghi una longword ciascuno, ed sono in pratica
una piccola memoria dentro il 68000, che di conseguenza e' molto veloce.
Tramite i registri si possono fare varie cose, infatti esiste una sintassi
particolare per i registri. Innanzitutto non si puo' lavorare per byte
con i registri INDIRIZZI: per esempio un move.b LABEL,a0 da un messaggio
di errore. Con i registri indirizzi a0,a1,etc si puo' dunque lavorare per
longword o per word. Con i registri Dati D0,D1,etc, invece si possono usare
sia .b che .w che .l. I registri indirizzi sono dedicati a contenere indirizzi,
ed hanno comandi dedicati, come il LEA, che significa LOAD ENTIRE ADDRESS,
ovvero carica l'indirizzo interamente nel registro (infatti questo comando non
puo' essere lea.b, lea.w o lea.l, ma solo LEA essendo sempre .L)
Per esempio, per mettere un valore nei registri indirizzi si possono usare
2 metodi:
1) MOVE.L #$50000,A0 (oppure MOVE.L #LABEL,a0)
2) LEA $50000,a0 (oppure LEA LABEL,A0)
Mentre il primo metodo si puo' usare sia con gli indirizzi che con i registri
(es: move.l #$50000,d0 - move.l #$50000,LABEL - MOVE.L #$LABEL,LABEL...)
P.S: scrivere move.l #$50000,d0 o MOVE.L #$50000,D0 e' identico, si puo'
scrivere anche MoVe.L #$50000,d0, il risultato a livello di programma
e' identico, solo che esteticamente potete creare delle situazioni
simpatiche o orribili. Va fatto un discorso diverso per le LABEL: le
label possono essere identificate anche se in un punto del listato le
scrivete in minuscolo e in un'altro in maiuscolo, questo pero' solo
perche' e' settata nelle preferenze del TRASH'M-ONE questa opzione,
che e' UCase=UCase nel menu' "Assembler/Assemble..", che significa
"Upper Case=Lower Case, ossia lettere grandi=lettere piccole".
Se togliete questa opzione, nel riconoscimento delle label sara' tenuto
presente anche il maiuscolo/minuscolo, per cui Cane: sara' diverso da
CANE: o da cAne: o da caNe, eccetera eccetera.
il secondo metodo con il LEA si puo' usare solo con i registri indirizzi,
di conseguenza si intuisce che questo modo e' piu' veloce: ricordatevi quindi
che se volete mettere un indirizzo in un registro a0,a1... dovete usare il
LEA seguito dall'indirizzo SENZA CANCELLETTO e dal registro in questione.
Fate attenzione a questi 2 esempi:
1) MOVE.L $50000,a0 ; metti in a0 il valore contenuto nella
; locazione $50000 (+$50001,$50002 e $50003
; in quanto 1 locazione e' lunga 1 byte, ed
; il move.l copia 4 bytes = 4 locazioni a
; partire in questo caso da $50000
2) LEA $50000,a0 ; metti il numero $50000 in a0
State attenti quindi a maneggiare i MOVE con o senza il cancelletto ed i LEA,
perche' e' facile nei primi tempi sbagliarsi e mettere l'indirizzo invece del
valore di quell'indirizzo nel registro o viceversa. Come ulteriore commento
di questa differenza consultate il programmino esempio LEZIONE2c.s
Con i registri indirizzi sono possibili vari tipi di indirizzamento:
Per cominciare analizziamo queste 2 istruzioni:
move.l a0,d0 ; Metti il numero contenuto in a0 nel registro d0
move.l (a0),d0 ; Metti la longword contenuta dall'indirizzo in a0
; nel registro d0
L'indirizzamento tra parentesi si dice INDIRETTO, perche' anziche' venir
copiato DIRETTAMENTE il valore in a0 viene copiato il valore contenuto
nell'indirizzo che e' in a0. Un esempio pratico e' in LEZIONE2d.s
Usando l'indirizzamento indiretto si puo' agire sugli indirizzi INDIRETTAMENTE,
ad esempio mettendo l'indirizzo del tasto del mouse e del colore 1 nei registri
si puo' riscrivere il listato della lezione 1. Cosi' ho fatto in LEZIONE2e.s
Facciamo gli ultimi esempi per togliere gli eventuali dubbi sull'indirizzamento
indiretto:
move.l a0,d0 ; copia il valore di A0 nel reg. d0
move.b (a0),d0 ; copia il byte contenuto nell'indirizzo
; in a0 nel reg. d0
move.w (a0),(a1) ; copia la word contenuta dall'indirizzo
; in a0 all'indirizzo contenuto in a1
; (e seguente, essendo una word fatta di
; 2 bytes, ossia 2 indirizzi!)
clr.w (a3) ; pulisce (azzera) la word (2 bytes) "dentro"
; l'indirizzo in a3 - Piu' precisamente,
; viene azzerato il byte dell'indirizzo in
; a3 e l'indirizzo seguente.
clr.l (a3) ; Come sopra, ma sono azzerati 4 indirizzi
; (una long = 4 bytes = 4 indirizzi)
move.l d0,(a5) ; viene copiato il valore di d0 nell'indirizzo
; contenuto in a5 ( piu' precisamente dovrei
; dire nell'indirizzo in a5, e nei 3 seguenti,
; in quanto una long occupa 4 indirizzi)
move.l d0,a5 ; viene copiato il valore di d0 in a5
Mi raccomando! Toglietevi ogni dubbio sugli indirizzamenti fin qui studiati,
consultando anche i sorgenti fino a LEZIONE2e.s, perche' gli indirizzamenti
di cui parlero' ora si basano su quelli indiretti normali.
Vi comunico che questa e' la parte piu' astratta della lezione2, in quanto
si devono imparare gli ultimi indirizzamenti del processore, ma vi assicuro
che gia' dalla lezione 3 metterete in pratica il tutto e visualizzerete degli
effetti video col copper!, quindi considerate che passata questa parte il resto
del corso sara' tutto piu' PRATICO: a ogni spiegazione corrispondera' un nuovo
effetto speciale o colore ultravivace, dunque fate lo sforzo di non annoiarvi
e di non lasciar perdere ora, perche' io stesso lasciai perdere all'incirca
a questo punto la prima volta che tentai di imparare a programmare in ASM,
proprio perche' ero scoraggiato dal CASINO di comandi e parentesi aperte e
chiuse che poi non riuscivo piu' a seguire. Vi assicuro pero' che una volta
imparato a leggere i comandi, potete partire come una fucilata e imparare
da voi leggendo listati qua' e la', facendo passi sempre piu' grandi: e'
come imparare le regole di uno sport: uno che non conosce il set di
istruzioni del 68000 e' come uno che non conosce le regole, ad esempio,
del calcio: guardando le partite (i listati) costui non capira' nulla di
cosa stanno facendo quegli scalmanati in un campo a dare calci ad una palla,
e si annoiera' a morte, ma una volta capite le regole (indirizzamenti) potra'
interpretare le fasi delle partite ed imparare sempre di piu' le tecniche
di gioco (i trucchi della programmazione ed i registri della grafica).
Vediamo altri 2 modi di indirizzamento:
move.l (a0)+,d0 ; Indiretto con post-incremento
move.l -(a0),d0 ; Indiretto con pre-decremento
Analizziamo il primo indirizzamento ipotizzando questa situazione:
lea NONNO,a0 ; mettiamo in a0 l'indirizzo di NONNO:
MOVE.L (a0)+,d0 ; mettiamo in d0 il valore .L contenuto
; dall'indirizzo in a0, ossia $3231020
; (come un normale MOVE.L (a0),d0)
; dopodiche' AGGIUNGIAMO 4 AL VALORE IN a0
; ovvero andiamo a PUNTARE alla long seguente
; con l'indirizzo in a0; se fosse stato un
; move.w (a0)+,d0 ad a0 DOPO (POST-INCREMENTO)
; sarebbe stato aggiunto 2 (una word=2),
; mentre nel caso di un MOVE.B (a0)+,d0
; sarebbe stato aggiunto 1, (un byte),
; ovvero sarebbe andato a puntare l'indirizzo
; seguente.
MOVE.L (a0)+,d1 ; stessa cosa: copia in d1 il valore .L
; contenuto nell'indirizzo in a0, che ora
; contiene l'indirizzo di NONNO+una longword,
; ovvero NONNO+4, ossia $13478.
rts ; ESCE!
NONNO:
dc.l $3231020,$13478
END
Possiamo tradurre questo tipo di indirizzamento con un 2 istruzioni:
1) MOVE.L (a0)+,LABEL
E' equivalente a:
1b) MOVE.L (A0),LABEL ; copia una long dall'indirizzo in a0
; nella label
ADDQ.W #4,a0 ; Aggiungi 4 ad a0 (.L=4)
; NOTA: se si addiziona un numero minore di
; 9 si usa il comando ADDQ invece di ADD
; perche' e' dedicato a tali numeri e veloce.
; Inoltre su registri INDIRIZZI se il numero
; che aggiungiamo o sottraiamo e' minore di
; $FFFF, ossia una word, si puo' usare il .W
; anziche' il .L, e si agira' comunque su
; tutta la longword dell'indirizzo.
Allo stesso modo:
2) MOVE.W (a0)+,LABEL
E' equivalente a:
2b) MOVE.W (A0),LABEL ; copia una word dall'indirizzo in a0
; nella label
ADDQ.W #2,a0 ; Aggiungi 2 ad a0 (.W=2)
Allo stesso modo:
3) MOVE.B (a0)+,LABEL
E' equivalente a:
3b) MOVE.B (A0),LABEL ; copia il byte contenuto nell'indirizzo
; in a0 nella label
ADDQ.W #1,a0 ; Aggiungi 1 ad a0 (.B=1)
Dunque, riassumendo in altri termini, l'indirizzamento indiretto con post
incremento si puo' paragonare ad un operaio di una catena di montaggio
che PRIMA esegue il suo MOVE o la sua istruzione sul pezzo che sta sul nastro
trasportatore, e ogni volta che ha fatto il suo lavoro sul pezzo sposta
AVANTI il nastro trasportatore(l'indirizzo in a0) con un pedale (il +).
Un esempio di loop puo' risultare piu' chiaro:
Inizio:
lea $60000,a0 ; inizio pulizia
lea $62000,a1 ; fine pulizia
CLELOOP:
clr.l (a0)+ ; azzera una long dall'indirizzo in A0 e aumenta a0
; di una long, ossia di 4 indirizzi, in altre
; parole pulisci una long e vai alla prossima
cmp.l a0,a1 ; A0 e' arrivato a $62000? Ossia, a0 e' uguale ad a1?
bne.s CLELOOP ; se non ancora, continua con un altro ciclo CLELOOP
rts
Come si vede, questo programmino pulisce la memoria dall'indirizzo $60000 a
$62000, utilizzando un clr (a0)+ ripetuto fino a che non si e' arrivati
all'indirizzo desiderato. Un esempio simile lo potete trovare in Lezione2f.s
Ora impareremo l'indirizzamento indiretto con pre-decremento, ossia un
indirizzamento opposto a quello appena descritto, infatti invece di aumentare
l'indirizzo contenuto rel registro dopo aver eseguito l'operazione, con
un clr.l -(a0), per esempio, prima viene decrementato a0, poi viene eseguita
l'istruzione sul nuovo indirizzo (in questo caso a0-4). Esempio:
lea NONNO,a0 ; mettiamo in a0 l'indirizzo di NONNO:
MOVE.L -(a0),d0 ; a0 viene decrementato, in questo caso
rts ; essendo un istruzione .L viene decrementato
; di 4, dopodiche' viene copiato in d0
; il valore .L contenuto dall'indirizzo
; in a0, ossia $12345678, cioe' NONNO-4
; (nel registro rimane il valore iniziale-4)
dc.l $12345678 ; se fosse stato un
NONNO: ; move.w -(a0),d0 ad a0 PRIMA (PRE-INCREMENTO)
dc.l $ffff0f0f ; sarebbe stato sottratto 2 (una word=2),
; mentre nel caso di un MOVE.B -(a0),d0
END ; sarebbe stato sottratto 1, (un byte),
; ovvero sarebbe andato a puntare l'indirizzo
; precedente.
Possiamo tradurre questo tipo di indirizzamento con un 2 istruzioni:
1) MOVE.L -(a0),LABEL
E' equivalente a:
1b) SUBQ.W #4,a0 ; Sottrai 4 ad a0 (.L=4)
; NOTA: se si sottrae un numero minore di
; 9 si usa il comando SUBQ invece di SUB
; perche' e' dedicato a tali numeri e veloce.
MOVE.L (A0),LABEL ; copia una long dall'indirizzo in a0
; nella label
Allo stesso modo:
2) MOVE.W -(a0),LABEL
E' equivalente a:
2b) SUBQ.W #2,a0 ; Sottrai 2 ad a0 (.W=2)
MOVE.W (A0),LABEL ; copia una word dall'indirizzo in a0
; nella label
Allo stesso modo:
3) MOVE.B -(a0),LABEL
E' equivalente a:
3b) SUBQ.W #1,a0 ; sottrai 1 ad a0 (.B=1)
MOVE.B (A0),LABEL ; copia il byte contenuto nell'indirizzo
; in a0 nella label
Riassumendo con l'operaio come prima, l'indirizzamento indiretto con pre
decremento si puo' paragonare sempre ad un operaio di una catena di montaggio
che PRIMA sposta INDIETRO il nastro trasportatore(l'indirizzo in a0) con un
pedale (il -), POI esegue il suo MOVE o la sua istruzione sul pezzo che sta
sul nastro trasportatore. Un esempio di loop:
Inizio:
lea $62000,a0 ; inizio pulizia
lea $60000,a1 ; fine pulizia
CLELOOP:
clr.l -(a0) ; diminuisci a0 di una long e azzera quella long
; in altre parole vai alla precedente long e puliscila
cmp.l a0,a1 ; A0 e' arrivato a $60000? Ossia, a0 e' uguale ad a1?
bne.s CLELOOP ; se non ancora, continua con un altro ciclo CLELOOP
rts
Come si vede, questo programmino pulisce la memoria dall'indirizzo $62000 a
$60000, utilizzando un clr -(a0) ripetuto fino a che non si e' arrivati
all'indirizzo desiderato (All'indietro pero'! mentre con (a0)+ si parte da
$60000 e di 4 in 4 si arriva a $62000, in questo caso si parte da $62000
e si arriva a $60000 indietreggiando di 4 in 4).
Vedete Lezione2g.s e Lezione2h.s per verificare gli ultimi 2 indirizzamenti.
Ora impareremo come usare la distanza di indirizzamento:
un MOVE.L $100(a0),d0 copia in d0 la long contenuta dall'indirizzo in a0+$100,
ossia: se per esempio in A0 avevamo l'indirizzo $60200, in d0 ci andra' la
longword contenuta dall'indirizzo $60300.
Allo stesso modo un MOVE.L -$100(a0),d0 copiera' in d0 la long a partire
dall'indirizzo $60100. Da notare che a0 non cambia di valore: semplicemente
il processore calcola ogni volta a che indirizzo operare, facendo la somma
tra il valore prima della parentesi e l'indirizzo nel registro tra parentesi.
La massima distanza di indirizzamento e' da -32768 a 32767 (-$7FFF, $8000)
Un esempio su questo tipo di indirizzamento e' Lezione2i.s
L'ultimo tipo di indirizzamento e' questo:
MOVE.L 50(a0,d0),label
che ha sia una DISTANZA DI INDIRIZZAMENTO (il 50) che un INDICE (il d0):
la distanza di indirizzamento e il contenuto di d0 sono tutti sommati per
definire l'indirizzo da cui copiare il contenuto. In pratica e' come la
distanza di indirizzamento, ma in piu' viene aggiunto anche il contenuto
dell'altro registro alla distanza di indirizzamento, che in questo caso
pero' va da un minimo di -128 ad un massimo di +128.
non vi voglio annoiare con altri esempi su questo indirizzamento, potrete
verificarlo quando lo troverete nei prossimi listati.
Per terminare la LEZIONE2, che se avete seguito bene vi rende in grado di
seguire le operazioni di un qualsiasi programma in ASM, e' indispensabile
spiegare il ciclo DBRA, che e' usato moltissimo: usando un registro dati
si possono far eseguire delle istruzioni varie volte, basta mettere nel
registro dati (sia esso d0,d1...) il numero di volte-1.
Ad esempio la routine che pulisce la memoria fatta con il CLR.l (a0)+ puo'
essere modificata con un loop DBRA che faccia eseguire la pulizia il
numero desiderato di volte:
Inizio:
lea $60000,a0 ; Inizio
move.l #($2000/4)-1,d0 ; Metti in d0 il numero di cicli necessari
; per cancellare $2000 bytes: cioe'
; $2000/4 (ovvero DIVISO 4, perche' ogni
; clr.l pulisce 4 bytes), il tutto -1,
; perche' il loop viene eseguito una volta
; in piu'.
CLEARLOOP:
CLR.L (a0)+
DBRA d0,CLEARLOOP
rts
Questa routine pulisce da $60000 a $62000 come l'esempio precedente in cui
con il comando CMP si COMPARA a0 con a1, ossia si verifica se siamo arrivati
a $62000 che e' in a1. In questo caso invece viene eseguito il CLR 2047 volte,
provate infatti a fare ?($2000/4)-1 da ASMONE. Il DBRA funziona in questo modo:
se per esempio la prima volta in d0 viene messo 2047, viene eseguito il CLR,
poi arrivati al DBRA d0 viene diminuito di 1 e il processore salta nuovamente
al CLR, lo esegue eccetera, fino a che d0 e' esaurito. Bisogna mettere il
numero di cicli necessari meno uno perche' la prima volta il ciclo viene
eseguito senza decrementare d0.
Come ultimo esempio studiatevi Lezione2l.s, che ha delle subroutines richiamate
con il BSR e il ciclo DBRA in azione, utile per capire la struttura di un
programma complesso.
Per terminare vorrei farvi notare la differenza tra un BSR ed un BEQ/BNE:
nel caso del BSR label, il processore salta ad eseguire la routine sotto la
label, fino a che non trova l'RTS, che lo fa tornare ad eseguire l'istruzione
sotto il BSR label, dunque si puo' dire che ha eseguito una SOTTOROUTINE, cioe'
una routine eseguita in mezzo ad un'altra routine:
principale:
move.l roba1,d0
move.l roba2,d1
bsr.s sottoposto
move.l roba3,d2
move.l roba4,d3
rts ; FINE DELLA ROUTINE PRINCIPALE, TORNA ALL'ASMONE
sottoposto:
move.l robaccia,d4
move.l robaccia2,d5
rts ; FINE DELLA SOTTOROUTINE, TORNA A "move.l roba3,d0", ossia
; sotto il bsr.s sottoposto
Nel caso di una DIRAMAZIONE beq/bne invece si prende O una strada O l'altra:
principale:
move.l roba1,d0
move.l roba2,a0
cmp.b d0,a0
bne.s strada2
move.l roba3,d1
cmp.b d1,a0
beq.s strada3
move.l roba4,d0
rts ; FINE DELLA ROUTINE PRINCIPALE, TORNA ALL'ASMONE
strada2:
move.l robaccia,d5
move.l robaccia2,d6
rts ; FINE ROUTINE, TORNA ALL'ASMONE, non sotto il bne!!!
; qua abbiamo scelto questa strada, e come si trova un RTS
; si torna all'ASMONE!!!
strada3:
move.l robaccia3,d1
move.l robaccia4,d2
rts ; FINE ROUTINE, TORNA ALL'ASMONE, non sotto il beq!!!
; qua abbiamo scelto questa strada, e come si trova un RTS
; si torna all'ASMONE!!!
Lo stesso vale per il BRA label, che significa SALTA A label, equivalente
del JMP, per cui e' come un treno che trova uno scambio ai binari, non torna
allo scambio quando ha finito il binario!! Arriva alla fine del binario e
basta, senza teletrasporti alla star trek all'indietro.
Per un'ultima precisazione sui registri indirizzi, vedetevi Lezione2m.s
Per caricare la LEZIONE3.TXT potete fare in due modi: o scrivete "R" e
andate a capo, facendo aprire il requester dove potete selezionare col mouse
quale testo caricare (in questo caso df0:SORGENTI/LEZIONE3.TXT), oppure
dovete assicurarvi di trovarvi nella directory giusta con un "V df0:LEZIONI"
e potete caricarla in seguito con un semplice "R LEZIONE3.TXT"